
import numpy as np
from math import sqrt
import dataDbControls as db
import logging



def setup_logging():
    """设置日志"""
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
    return logging.getLogger(__name__)

logger = setup_logging()


class TxdClass:

    def tdx_double_wma_single_param(self,close_prices, n):
        """
        正确的实现方式：只需要一个参数N
        内部自动计算三个不同的周期
        """
        # 在函数内部计算三个周期参数
        period1 = int(round(n / 2))  # ROUND(N/2)
        period2 = n  # 直接使用N
        period3 = int(round(sqrt(n)))  # ROUND(SQRT(N))

        logger.info(f"参数分解: N={n} -> 周期1={period1}, 周期2={period2}, 周期3={period3}")

        # 计算第一个WMA（短期）
        wma_short = self.weighted_moving_average(close_prices, period1)

        # 计算第二个WMA（长期）
        wma_long = self.weighted_moving_average(close_prices, period2)

        # 计算趋势差值
        trend_diff = 2 * wma_short - wma_long

        # 对差值进行最终平滑
        result = self.weighted_moving_average(trend_diff, period3)

        # 方法1: 使用负索引切片
        last = result[-1:]
        # 方法2B: 使用values属性
        last_m = last[0]
        if(last_m=="nan"):
            return "\n"
        else:
            return  f"赫尔均线_{n}线为: {last_m}\n"


    def weighted_moving_average(self,data, period):
        """
        加权移动平均计算函数
        """
        if len(data) < period:
            return np.full(len(data), np.nan)

        weights = np.arange(1, period + 1)
        weights_sum = weights.sum()

        result = np.full(len(data), np.nan)

        for i in range(period - 1, len(data)):
            window = data[i - period + 1: i + 1]
            wma_value = np.sum(window * weights) / weights_sum
            result[i] = wma_value

        return result




    # # 字段名称 数据类型 字段说明
    # # t string 交易时间
    # # o float 开盘价
    # # h float 最高价
    # # l float 最低价
    # # c float 收盘价
    # # v float 成交量
    # # a float 成交额
    # # pc float 前收盘价
    # # sf int 停牌 1 停牌，0  不停牌
    #
    # #获取通信达分钟级别的数据
    # # txd_kdj(df)

    def txd_kdj(self,df,n, m1, m2,row):
        # 计算KDJ
        k, d, j = self.calculate_kdj_manual_match(
            high=df['最高价'].values,
            low=df['最低价'].values,
            close=df['收盘价'].values,
            n =n,
            m1 =m1,
            m2 =m2
        )

        df['kdj_k'] = k
        df['kdj_d'] = d
        df['kdj_j'] = j
        logger.info(df[['时间','最高价', '最低价', '收盘价', 'kdj_k', 'kdj_d', 'kdj_j']].tail(60))


        '''
        卖出策略: 
        1.当前值小于上一个值，且上一个值大于100,当前值小于100 则触发卖出告警
        2.如当前值大于100，则不告警卖出
        '''

        # 获取最后3行
        # 方法1: 使用负索引切片
        l1 = df[-1:]
        logger.info("使用df[-1:]获取最后1行:")
        logger.info(l1[['时间','最高价', '最低价', '收盘价', 'kdj_k', 'kdj_d', 'kdj_j']])


        a1 =l1['kdj_j'].iloc[0]
        atime =l1['时间'].iloc[0]

        # 只有当小于100的时候才去考虑它告警 走那个方向
        if(a1 <100):
            # 使用示例
            # alarm =insert.AlarmNotificationEntry(
            #     stock_rules_id = 1,
            #     stock_code ="775",
            #     time_period = "5",
            #     alarm_description ="",
            # )

           a2= df[-2:-1]['kdj_j'].iloc[0]

            # 说明是卖出信号 来临 提示卖出
           if(a1 < 100 and a2 >=100):
               #告警写入适配
               db.insert_alarm_writing(row['stock_code'],row['id'],row['time_period'],atime,'进入卖点范围,请跟进')
               logger.info(f"卖出提示写入成功")


           '''买入策略
              1.当前j小于0 就触发告警，不考虑后续是否持续降低，
              2.当前值小于上一个值 切都小于0 那么不持续告警
           '''
           # 说明是买入信号 来临 提示买入
           if (a1 > 0 and a2 < 0):
               #告警写入适配
               db.insert_alarm_writing(row['stock_code'],row['id'],row['time_period'],atime,'进入买入点范围,请跟进')
               logger.info(f"买入提示写入成功")



        # 方法1: 使用负索引切片
        # last_3_slice = df[-2:-1]
        # print("使用df[-2:]获取最后3行:")
        # print(last_3_slice[['时间','最高价', '最低价', '收盘价', 'kdj_k', 'kdj_d', 'kdj_j']])







        #
        # # 方法1A: 使用正确的索引
        # correct_index = last_3_slice.index[0]
        # j_local_time = last_3_slice.loc[correct_index, '时间']
        # x = last_3_slice.loc[correct_index, 'kdj_j']
        # if(x < 0):
        #     res =f"指标时间:{j_local_time},j值为:{x}\n"
        #     return  res
        # elif(x >100):
        #     res =f"指标时间:{j_local_time},j值为:{x}\n"
        #     return  res
        # else:
        #     return  ""


        # 使用 itertuples() 循环
        # for row in last_3_slice.itertuples():
        #     # 注意：索引可以通过 row.Index 访问，数据通过 row.列名 访问
        #     # print(row['时间', '最高价', '最低价', '收盘价', 'kdj_k', 'kdj_d', 'kdj_j'])
        #     print(f"时间: {row.时间}, 最高价: {row.最高价}, 最低价: {row.最低价}, 收盘价: {row.收盘价},kdj_k: {row.kdj_k},kdj_d: {row.kdj_d},kdj_j: {row.kdj_j}")





    def calculate_kdj_manual_match(self,high, low, close, n, m1, m2):
        """
        手动计算KDJ，完全匹配通达信算法
        """
        # 确保输入是numpy数组
        high = np.asarray(high, dtype=np.float64)
        low = np.asarray(low, dtype=np.float64)
        close = np.asarray(close, dtype=np.float64)

        # 初始化结果数组
        k_values = np.full_like(close, np.nan)
        d_values = np.full_like(close, np.nan)
        j_values = np.full_like(close, np.nan)

        # 计算每个点的KDJ
        for i in range(n - 1, len(close)):
            # 计算RSV
            low_min = np.min(low[i - n + 1:i + 1])
            high_max = np.max(high[i - n + 1:i + 1])

            if high_max != low_min:
                rsv = (close[i] - low_min) / (high_max - low_min) * 100
            else:
                rsv = 50  # 避免除零

            # 计算K值（通达信SMA算法）
            if i == n - 1:  # 第一个有效点
                k_values[i] = rsv
            else:
                k_prev = k_values[i - 1] if not np.isnan(k_values[i - 1]) else rsv
                k_values[i] = (rsv * 1 + k_prev * (m1 - 1)) / m1

            # 计算D值（通达信SMA算法）
            if i == n - 1:  # 第一个有效点
                d_values[i] = k_values[i]
            else:
                d_prev = d_values[i - 1] if not np.isnan(d_values[i - 1]) else k_values[i]
                d_values[i] = (k_values[i] * 1 + d_prev * (m2 - 1)) / m2

            # 计算J值
            j_values[i] = 3 * k_values[i] - 2 * d_values[i]

        return k_values, d_values, j_values

